package com.water.app.Impl.shopping;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.water.app.*;
import com.water.app.Exceptions.BalanceException;
import com.water.app.Exceptions.StockException;
import com.water.app.interfaces.account.EmailService;
import com.water.app.interfaces.shopping.ShoppingService;
import com.water.app.mapper.goodsMapper;
import com.water.app.mapper.shoppingMapper;
import com.water.app.mapper.userMapper;
import jakarta.annotation.PostConstruct;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.ThreadPoolExecutor;

@Service
public class ShoppingServiceImpl implements ShoppingService {
    private static final Logger log = LoggerFactory.getLogger(ShoppingServiceImpl.class);

    private shoppingMapper shoppingMapper;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private userMapper userMapper;
    @Autowired
    private goodsMapper goodsMapper;
    @Autowired
    private ThreadPoolExecutor poolExecutor;
    @Autowired
    private EmailService emailService;

    @Autowired
    public ShoppingServiceImpl(BlockingDeque<GoodsIdListAndUserId> qeque,shoppingMapper shoppingMapper) {
        this.qeque = qeque;
        this.shoppingMapper=shoppingMapper;
    }
    public ShoppingServiceImpl(BlockingDeque<GoodsIdListAndUserId> qeque){
        this.qeque=qeque;
    }


    @Override
    public boolean deleteGoodsById(int userId, int goodsId) {
        return shoppingMapper.deleteGoodsSingleById(userId, goodsId) == 1;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateGoodsArbitrary(Map<Integer, Integer> errorMap, Map<Integer, Integer> successMap){
        for (Map.Entry<Integer, Integer> entry : successMap.entrySet()) {
            int goodsId = entry.getKey();
            int number = entry.getValue();
            int affectRows = shoppingMapper.updateGoodsArbitrary(goodsId, number);
            if (affectRows == 0) {
                //手动回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                log.info("库存不足");
                return false;
            } else {
                log.info("编号为{}的商品更新成功", goodsId);
                successMap.put(goodsId, number);
            }
        }
        log.info("库存扣减成功");
        return true;
    }


    @Override
    public List<Map<Integer, Double>> countGoodsPriceOneByOne(int userId) {
        return shoppingMapper.countGoodsPriceOneByOne(userId);
    }



    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean Checkout(Map<Integer, Integer> successMap, int userId) {
        double total = 0;
        for (Map.Entry<Integer, Integer> entry : successMap.entrySet()) {
            int goodsId = entry.getKey();
            int number = entry.getValue();
            int sellerId = goodsMapper.selectUserByGoodsId(goodsId);
            double singleMoney = goodsMapper.selectSingleMoneyByGoodsId(goodsId);
            double sum = number * singleMoney;
            int affectRows= userMapper.increaseMoney(sellerId, sum);
            if (affectRows==0) {
                log.info("卖家加钱失败");
                //手动回滚事务
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return false;
            }
            total = total + sum;
        }
        int affectRows=userMapper.decreaseMoney(userId,total);
        if(affectRows> 0){
            log.info("买家支付成功");
            return true;
        }else {
            log.info("余额不足");
            //手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }
    }

    @Override
    public int selectGoodsCount(int goodsId) {
        return shoppingMapper.selectGoodsCountById(goodsId);
    }


    @Override
    public boolean insertCart(int userId, int goodsId, int number) {
        int exist= shoppingMapper.selectCartIsExist(userId,goodsId);
        //购物车不存在且商品数量大于零就新建购物车
        if(exist<=0&&number>0){
            return shoppingMapper.insertCart(userId, goodsId, number) > 0;
            //购物车不存在但是数量为0或负数就用户输入错误
        }else if(exist<=0&&number<=0){
            return false;
            //如果购物车存在，但是商品数量设置为零，就是删除购物车
        }else if(exist>0&&number<=0){
            return shoppingMapper.deleteGoodsSingleById(userId,goodsId)>0;
            //如果购物车存在且商品数量大于0，则修改购物车信息
        }else if (exist>0&&number>0){
            return shoppingMapper.updateCartArbitrary(userId,goodsId,number)>0;
        }
        return false;
    }

    @Override
    public List<Goods> showCart(int userId) {
        return shoppingMapper.showCart(userId);
    }



//    @Transactional(rollbackFor = Exception.class)
//    @Override
//    public boolean pay(List<Integer> goodsIdList, int userId) throws StockException, BalanceException {
//        double sum=0;
//        log.info("userId:{}",userId);
//        for(int goodsId:goodsIdList){
//            log.info("goodsId:{}",goodsId);
//            //商品
//            Goods goods= shoppingMapper.selectGoodsById(goodsId);
//            log.info("goods:{}",goods);
//            //商品单价
//            double money=goods.getPrice();
//            //用户所需商品数量
//            int number=shoppingMapper.selectCartGoodsNumber(userId,goodsId);
//            //总价
//            double total=money*number;
//            //查询卖家用户id
//            int id=shoppingMapper.selectUserIdByGoodsId(goodsId);
//            //减库存
//            int affectRows1=shoppingMapper.updateGoodsArbitrary(goodsId,number);
//            if(affectRows1==0){
//                log.info("库存不足");
//                throw new StockException("库存不足");
//            }
//            //加钱
//            int affectRows2= shoppingMapper.increaseUserMoney(total,id);
//            log.info("affectRows2:{}",affectRows2);
//            if(affectRows2==0){
//                log.info("加钱错误");
//                throw new BalanceException("加钱错误");
//            }
//            //进入订单记录
//            int affectRows4=shoppingMapper.intoOrders(goods,userId,number);
//            if(affectRows4==0){
//                log.info("订单插入失败");
//                throw new BalanceException("订单插入失败");
//            }
//            sum=sum+total;
//            shoppingMapper.deleteGoodsSingleById(userId,goodsId);
//        }
//        int affectRows3=shoppingMapper.decreaseUserMoney(userId,sum);
//        log.info("标记12");
//        if(affectRows3==0){
//            log.info("余额不足");
//            throw new BalanceException("余额不足");
//        }
//        return true;
//    }
    public static final ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(10,
        12,
        30,
        TimeUnit.SECONDS,
        new LinkedBlockingDeque(1000));

    @Autowired
    private final BlockingDeque<GoodsIdListAndUserId> qeque;

    @PostConstruct
    public void startConsumer() {
        // 启动多个消费者线程，提高处理效率
        for (int i = 0; i < 10; i++) {
            threadPoolExecutor.execute(new Consumer(qeque,this));
        }
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void consumerPay(List<Integer> goodsIdList, int userId,Integer addressId) throws StockException, BalanceException {
        double sum = 0;
        for (int goodsId : goodsIdList) {
            //商品
            Goods goods = shoppingMapper.selectGoodsById(goodsId);
            log.info("goods:{}", goods);
            //商品单价
            double money = goods.getPrice();
            //用户所需商品数量
            int number = shoppingMapper.selectCartGoodsNumber(userId, goodsId);
            //总价
            double total = money * number;
            //查询卖家用户id
            int id = shoppingMapper.selectUserIdByGoodsId(goodsId);
            //减库存
            int affectRows1 = shoppingMapper.updateGoodsArbitrary(goodsId, number);
            if (affectRows1 == 0) {
                log.info("库存不足");
                throw new StockException("库存不足");
            }
            //加钱
            int affectRows2 = shoppingMapper.increaseUserMoney(total, id);
            log.info("affectRows2:{}", affectRows2);
            if (affectRows2 == 0) {
                log.info("加钱错误");
                throw new BalanceException("加钱错误");
            }
            //进入订单记录
            int affectRows4 = shoppingMapper.intoOrders(goods, userId, number);
            if (affectRows4 == 0) {
                log.info("订单插入失败");
                throw new BalanceException("订单插入失败");
            }
            sum = sum + total;
            shoppingMapper.deleteGoodsSingleById(userId, goodsId);
        }
        int affectRows3 = shoppingMapper.decreaseUserMoney(userId, sum);
        if (affectRows3 == 0) {
            log.info("余额不足");
            throw new BalanceException("余额不足");
        }
        try {
            address address=this.selectAddressById(addressId);
            emailService.sendEmail(address.getEmail(),address.getAddress(),address.getName());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    class GoodsIdListAndUserId{
        List<Integer> goodsIdList;
        Integer userId;
        Integer addressId;

        public Integer getAddressId() {
            return addressId;
        }

        public void setAddress(Integer address) {
            this.addressId = address;
        }

        public GoodsIdListAndUserId(Integer userId, List<Integer> goodsIdList,Integer addressId) {
            this.userId = userId;
            this.goodsIdList = goodsIdList;
            this.addressId=addressId;
        }

        public List<Integer> getGoodsIdList() {
            return goodsIdList;
        }

        public void setGoodsIdList(List<Integer> goodsIdList) {
            this.goodsIdList = goodsIdList;
        }

        public Integer getUserId() {
            return userId;
        }

        public void setUserId(Integer userId) {
            this.userId = userId;
        }
    }
    @Override
    public boolean pay(List<Integer> goodsIdList, int userId,Integer addressId) throws StockException, BalanceException, InterruptedException {
        GoodsIdListAndUserId goodsIdListAndUserId=new GoodsIdListAndUserId(userId, goodsIdList,addressId);
        boolean result = qeque.offer(goodsIdListAndUserId, 3, TimeUnit.SECONDS);
        if(!result){
            throw new RuntimeException("业务繁忙请稍后尝试");
        }
        return true;
    }

    @Override
    public Result sKill(int goodsId) {
        int userId = Constant.THREAD_LOCAL.get();

        //  1. 使用商品级锁
        RLock lock = redissonClient.getLock(Constant.SECKILL_LOCK + goodsId);

        try {
            // 尝试获取锁（防死锁）
            boolean isLocked = lock.tryLock(1, 30, TimeUnit.SECONDS);
            if (!isLocked) {
                return Result.error("请求过于频繁，请稍后重试");
            }


            //  2. 从 Redis Hash 中获取商品信息
            Object obj = stringRedisTemplate.opsForHash().get(Constant.SKILL, String.valueOf(goodsId));
            if (obj == null) {
                return Result.error("商品不存在");
            }

            Goods goods = objectMapper.readValue(obj.toString(), Goods.class);
            if (goods.getCount() <= 0) {
                return Result.error("库存已售罄");
            }

            //  3. 判断用户是否已抢过（可选：用 set 记录）
            Boolean isExist = stringRedisTemplate.opsForSet()
                    .isMember(Constant.SECKILL_USER + goodsId, String.valueOf(userId));
            if (Boolean.TRUE.equals(isExist)) {
                return Result.error("你已抢过该商品");
            }

            double money = shoppingMapper.selectUserMoney(userId);
            if (money < goods.getPrice()) {
                return Result.error("余额不足");
            }

            //  4. 扣减 Redis 库存（原子操作）
            DefaultRedisScript<Long> script = new DefaultRedisScript<>(
                    "local stock = redis.call('hget', KEYS[1], ARGV[1]) " +
                            "if not stock or tonumber(stock) <= 0 then return 0 end " +
                            "if tonumber(stock) >= 1 then " +
                            "   redis.call('hincrby', KEYS[1], ARGV[1], -1) " +
                            "   return 1 " +
                            "else " +
                            "   return 0 " +
                            "end",
                    Long.class
            );

            Long result = stringRedisTemplate.execute(
                    script,
                    Arrays.asList(Constant.SKILL),
                    String.valueOf(goodsId)
            );

            if (result == 0) {
                return Result.error("库存不足");
            }

            //  5. 添加用户抢购记录（防重）
            stringRedisTemplate.opsForSet().add(Constant.SECKILL_USER + goodsId, String.valueOf(userId));


            shoppingMapper.decreaseGoodsCount(goodsId);

            shoppingMapper.decreaseUserMoney(userId, goods.getPrice());

            return Result.success("秒杀成功！");

        } catch (Exception e) {
            log.error("秒杀异常", e);
            return Result.error("系统异常");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public address selectAddressById(Integer id) {
        return shoppingMapper.selectAddressById(id);
    }

}
